package com.shu.lock;

import com.google.common.base.Stopwatch;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @author ssm
 * @version V1.0
 * @description:
 * @date 2020/8/27 17:40
 */

public class Read_write_lock {

    public static ReentrantReadWriteLock readWriteLock1 = new ReentrantReadWriteLock();
    public static ReentrantReadWriteLock readWriteLock2 = new ReentrantReadWriteLock();
    public static ReentrantReadWriteLock readWriteLock3 = new ReentrantReadWriteLock();
    public static ReentrantReadWriteLock readWriteLock4 = new ReentrantReadWriteLock();
    public static ReentrantReadWriteLock readWriteLock5 = new ReentrantReadWriteLock();

    public static void main(String[] args) throws InterruptedException {
//        test1();
//        test2();
        // 读锁可以被多个线程同时获取
        test3();

        // 写锁同时只能被一个线程获取使用
        test4();


        // 读锁被线程占用时,写锁被阻塞
        test5();

    }

    private static void test5() throws InterruptedException {
        System.out.println("-------------读锁被线程占用时-------------------------");
        CountDownLatch countDownLatch = new CountDownLatch(2);

        Thread t1 = new Thread(() -> {
            readWriteLock5.readLock().lock();
            System.out.println("t1读操作");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                countDownLatch.countDown();
                System.out.println("t1读锁释放");
                readWriteLock5.readLock().unlock();
            }
        }, "t1");


        Thread t2 = new Thread(() -> {
            readWriteLock5.writeLock().lock();
            System.out.println("t2写操作");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                countDownLatch.countDown();
                System.out.println("t2写锁释放");
                readWriteLock5.writeLock().unlock();
            }
        }, "t2");

        Stopwatch watch = Stopwatch.createStarted();

        t1.start();
        t2.start();

        countDownLatch.await();
        System.out.println("写操作完毕!耗时: " + watch.elapsed(TimeUnit.SECONDS) + " 秒");

    }

    private static void test4() throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(2);

        Thread t1 = new Thread(() -> {
            readWriteLock4.writeLock().lock();
            System.out.println("写操作");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                countDownLatch.countDown();
                System.out.println("t1写锁释放");
                readWriteLock4.writeLock().unlock();
            }
        }, "t1");


        Thread t2 = new Thread(() -> {
            readWriteLock4.writeLock().lock();
            System.out.println("写操作");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                countDownLatch.countDown();
                System.out.println("t2写锁释放");
                readWriteLock4.writeLock().unlock();
            }
        }, "t2");


        Stopwatch watch = Stopwatch.createStarted();

        t1.start();
        t2.start();

        countDownLatch.await();
        System.out.println("写操作完毕!耗时: " + watch.elapsed(TimeUnit.SECONDS) + " 秒");
    }

    /**
     * 读锁可以被多个线程同时获取
     * @throws InterruptedException
     */
    private static void test3() throws InterruptedException {

        CountDownLatch countDownLatch = new CountDownLatch(2);

        Thread t1 = new Thread(() -> {
            readWriteLock3.readLock().lock();
            System.out.println("读操作");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                countDownLatch.countDown();
            }
        }, "t1");


        Thread t2 = new Thread(() -> {
            readWriteLock3.readLock().lock();
            System.out.println("读操作");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                countDownLatch.countDown();
            }
        }, "t2");


        Stopwatch watch = Stopwatch.createStarted();

        t1.start();
        t2.start();

        countDownLatch.await();

        System.out.println("读操作完毕!耗时: " + watch.elapsed(TimeUnit.SECONDS) + " 秒");

    }

    private static void test2() {
        readWriteLock1.readLock().lock();
        System.out.println("获取读锁");
        readWriteLock1.writeLock().lock();
        System.out.println("获取读锁");
        System.out.println("读写锁可以升级!");
    }

    private static void test1() {
        readWriteLock2.writeLock().lock();
        System.out.println("获取写锁");
        readWriteLock2.readLock().lock();
        System.out.println("获取读锁");
        System.out.println("读写锁可以降级!");
    }


}
